/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.util;

import java.io.InvalidObjectException;

/**
 * 这个类实现Set接口，由一个散列表(实际上是一个HashMap实例)支持。
 * 它不保证集合的迭代顺序;特别是，它不能保证顺序保持不变。该类允许null元素。
 *
 * <p>这个类为基本操作(add,remove,contains,size)提供了常数时间性能，假设散列函数正确地将元素分散到各个桶中。
 * 遍历这个集合需要的时间与HashSet实例的大小(元素的数量) 加上 支持HashMap实例的“容量”(桶的数量)的总和成比例。
 * 因此，如果迭代性能很重要，那么不要将初始容量设置得太高(或负载因子太低)是非常重要的。
 *
 * <p>注意，这个实现不是同步的。如果多个线程同时访问一个散列集，
 * 并且至少有一个线程修改该散列集，则必须在外部对其进行同步。
 * 这通常是通过对一些自然封装了集合的对象进行同步来实现的。
 * 
 * 如果不存在这样的对象，则应该使用Collections.synchronizedSet方法来保证它。
 * 这最好在创建时完成，以防止意外的不同步的访问set的行为:
 *
 * <pre>
 *   Set s = Collections.synchronizedSet(new HashSet(...));</pre>
 *
 * <p>这个类的迭代器方法返回的迭代器是快速失效的:如果在迭代器创建后的任何时候修改集合，
 * 除了通过迭代器自己的删除方法之外，任何方式都可以，迭代器抛出ConcurrentModificationException。
 * 因此，在面对并发修改时，迭代器会快速而干净地失败，而不是在将来某个不确定的时间冒任意的、不确定的行为的风险。
 *
 * <p>注意，不能保证迭代器的快速故障行为，因为通常来说，在存在非同步并发修改的情况下，不可能做出任何严格的保证。
 * 故障快速迭代器在最大努力的基础上抛出ConcurrentModificationException。
 * 因此，编写一个依赖于这个异常的正确性的程序是错误的:迭代器的快速故障行为应该只用于检测bug。
 *
 * @param <E> the type of elements maintained by this set
 *
 * @author  Josh Bloch
 * @author  Neal Gafter
 * @see     Collection
 * @see     Set
 * @see     TreeSet
 * @see     HashMap
 * @since   1.2
 */

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    static final long serialVersionUID = -5024744406713321676L;

    // 内置了一个map
    private transient HashMap<E,Object> map;

    // map.put(e, PRESENT) 作为map里的value
    // PRESENT是static final的常量，所有hashset共享
    private static final Object PRESENT = new Object();

    /**
     * 创建一个新的，空的set，依赖的HashMap实例是默认的，初始容量为16，初始负载因子为0.75
     */
    public HashSet() {
        map = new HashMap<>();
    }

    /**
     * 构造一个新集合，该集合包含指定集合中的元素。
     * HashMap是使用默认的负载因子(0.75)和足够容纳指定集合中的元素的初始容量创建的。
     *
     * @param c the collection whose elements are to be placed into this set
     * @throws NullPointerException if the specified collection is null
     */
    public HashSet(Collection<? extends E> c) {
    	// c的size/0.75 +1 为容量  ，最小为16
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }

    /**
     * 构造一个新的空集;支持的HashMap实例具有指定的初始容量和指定的负载因子。
     * 
     * @param      initialCapacity   the initial capacity of the hash map
     * @param      loadFactor        the load factor of the hash map
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero, or if the load factor is nonpositive
     */
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }

    /**
     * 构造一个新的空集;支持的HashMap实例具有指定的初始容量和缺省负载因子(0.75)。
     *
     * @param      initialCapacity   the initial capacity of the hash table
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero
     */
    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }

    /**
     * 构造一个新的空的链接哈希集(这个包的私有构造函数只被LinkedHashSet使用)。
     * 支持的HashMap实例是一个LinkedHashMap，它具有指定的初始容量和指定的负载因子。
     *
     * @param      initialCapacity   the initial capacity of the hash map
     * @param      loadFactor        the load factor of the hash map
     * @param      dummy             ignored (distinguishes this
     *             constructor from other int, float constructor.)
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero, or if the load factor is nonpositive
     */
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }

    /**
     * 在这个集合的元素上返回一个迭代器。元素没有按照特定的顺序返回。
     *
     * @return an Iterator over the elements in this set
     * @see ConcurrentModificationException
     */
    public Iterator<E> iterator() {
    	// 返回map的keySet视图的迭代器
        return map.keySet().iterator();
    }

    /**
     * 返回此集合中的元素
     *
     * @return the number of elements in this set (its cardinality)
     */
    public int size() {
        return map.size();
    }

    /**
     * 如果该集合不包含元素，则返回true。
     *
     * @return <tt>true</tt> if this set contains no elements
     */
    public boolean isEmpty() {
        return map.isEmpty();
    }

    /**
     * 如果set包含指定元素，返回true。
     * 更正式地，当且仅当集合至少有一个这样的元素时，返回true。
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
     *
     * @param o element whose presence in this set is to be tested
     * @return <tt>true</tt> if this set contains the specified element
     */
    public boolean contains(Object o) {
    	// map是否有这个key
        return map.containsKey(o);
    }

    /**
     * <p>如果set没有指定元素，将指定元素加入set。
     * 更正式地说，如果set不包含元素e2，有指定元素e，
     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>
     * 将e加入到set。
     * 
     * <p>如果set已经包含了这个元素，调用让set不改变，并且返回false。
     * 
     * @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     * element
     */
    public boolean add(E e) {
    	// key为e，value为一个常量 new Object()
        return map.put(e, PRESENT)==null;
    }

    /**
     * 如果指定元素存在，从set中移除指定元素（可选的操作）。
     * 更正式地说，如果set包含一个这样的元素，就移除一个这样的元素 ，
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>
     * 如果集合包含指定元素，返回true。（如果集合因为调用而改变，返回true）
     * (调用结束后，set不会包含这个元素）
     *
     * @param o object to be removed from this set, if present
     * @return <tt>true</tt> if the set contained the specified element
     */
    public boolean remove(Object o) {
    	// map移除key为o
        return map.remove(o)==PRESENT;
    }

    /**
     * 移除set中所有的元素
     */
    public void clear() {
        map.clear();
    }

    /**
     * 返回此HashSet实例的浅拷贝:元素本身没有被克隆。
     *
     * @return a shallow copy of this set
     */
    @SuppressWarnings("unchecked")
    public Object clone() {
        try {
        	// 对自己进行浅拷贝
            HashSet<E> newSet = (HashSet<E>) super.clone();
            // 对map进行浅拷贝
            newSet.map = (HashMap<E, Object>) map.clone();
            return newSet;
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
    }

    /**
     * 将这个HashSet实例的状态保存到流中(即序列化它)。
     *
     * @serialData The capacity of the backing <tt>HashMap</tt> instance
     *             (int), and its load factor (float) are emitted, followed by
     *             the size of the set (the number of elements it contains)
     *             (int), followed by all of its elements (each an Object) in
     *             no particular order.
     */
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        // 写出隐藏的字段。
        s.defaultWriteObject();

        // 写出HashMap的容量和负载因子
        s.writeInt(map.capacity());
        s.writeFloat(map.loadFactor());

        // 写出size
        s.writeInt(map.size());

        // 以适当的顺序写出所有的元素
        for (E e : map.keySet())
            s.writeObject(e);
    }

    /**
     * 从流中重新构造HashSet实例(即反序列化它)。
     */
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // 读入隐藏字段
        s.defaultReadObject();

        // 读入容量，验证非负
        int capacity = s.readInt();
        if (capacity < 0) {
            throw new InvalidObjectException("Illegal capacity: " +
                                             capacity);
        }

        // 读入负载因子，验证整数和不是NaN
        float loadFactor = s.readFloat();
        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
            throw new InvalidObjectException("Illegal load factor: " +
                                             loadFactor);
        }

        // 读入size，验证非负
        int size = s.readInt();
        if (size < 0) {
            throw new InvalidObjectException("Illegal size: " +
                                             size);
        }

        // 根据size和负载因子，设置容量，保证HashMap至少是25%是满的，但是小于最大容量
        capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
                HashMap.MAXIMUM_CAPACITY);

        // 创建支持的HashMap，安装上面得到的capacity和loadFactor
        // 根据自己是HashSet还是LinkedHashSet，创建HashMap，LinkedHashMap
        map = (((HashSet<?>)this) instanceof LinkedHashSet ?
               new LinkedHashMap<E,Object>(capacity, loadFactor) :
               new HashMap<E,Object>(capacity, loadFactor));

        // 以适当的顺序读入所有的元素
        for (int i=0; i<size; i++) {
            @SuppressWarnings("unchecked")
                E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }

    /**
     * 在这个集合的元素上创建一个迟绑定和快速失败的Spliterator。
	 * Spliterator报告SIZED和DISTINCT。覆盖的实现应该记录额外特征值。
     *
     * @return a {@code Spliterator} over the elements in this set
     * @since 1.8
     */
    public Spliterator<E> spliterator() {
    	// 返回HashMap的keySpliterator
        return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0);
    }
}
